import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

// 获取sd卡根目录
Future<String> getStoragePath() async {
  Directory? directory = Platform.isAndroid
      ? await getExternalStorageDirectory()
      : await getApplicationSupportDirectory();
  return directory!.path;
}

// 下载工具
class DownloadUtils {
  // 下载路径
  static String downloadUrl = '';
  // 下载保存路径
  static late String downloadPath;
  // 下载任务id
  static String? _taskId;
  // 下载文件名
  static late String filename;
  static void Function(String, DownloadTaskStatus, int)? _callback;

  static const String portName = 'downloader_send_port';

  // 初始化
  static Future<dynamic> init() async {
    dispose();
    // 获取下载保存路径
    downloadPath = await FileUtils.downloadPath;
    // 判断是否有下载，没有就创建
    FileUtils.mkdirp(downloadPath);

    // 监听下载进度和下载结果
    ReceivePort _port = ReceivePort();
    IsolateNameServer.registerPortWithName(_port.sendPort, portName);
    _port.listen((data) async {
      String id = data[0];
      DownloadTaskStatus status = data[1];
      int progress = data[2];

      // 下载完成
      if (status == DownloadTaskStatus.complete) {
        // 文件保存到文件管理器
        // 获取最新的下载文件名
        List<DownloadTask>? list = await FlutterDownloader.loadTasks();
        if (list != null && list.length > 0) {
          filename = list[list.length - 1].filename ?? '';
        }

        _taskId = null;
      } else if (status == DownloadTaskStatus.failed) {
        Fluttertoast.showToast(msg: '下载失败');
      }

      // 触发回调函数
      if (_callback != null) {
        _callback!(id, status, progress);
      }
    });
    // 注册回调函数
    FlutterDownloader.registerCallback(downloadCallback);
  }

  // 监听下载情况
  static void downloadCallback(
      String id, DownloadTaskStatus status, int progress) {
    SendPort? sendPort = IsolateNameServer.lookupPortByName(portName);
    sendPort!.send([id, status, progress]);
  }

  // 销毁
  static void dispose() {
    downloadUrl = '';
    _taskId = null;
    IsolateNameServer.removePortNameMapping(portName);
  }

  // 下载
  static Future<String?> download({
    required String url,
    Function(String, DownloadTaskStatus, int)? callback,
    bool showNotification = true,
    bool openFileFromNotification = false,
  }) async {
    downloadUrl = url;
    // 设置回调函数
    if (callback != null) {
      _callback = callback;
    }

    if (await _requestPermission()) {
      if (_taskId != null) {
        Fluttertoast.showToast(msg: '有正在下载的任务');
      } else if (downloadUrl.isEmpty) {
        Fluttertoast.showToast(msg: '下载地址不能为空');
      } else {
        // 开始下载
        _taskId = await FlutterDownloader.enqueue(
          url: downloadUrl,
          savedDir: downloadPath,
          showNotification: showNotification,
          openFileFromNotification: openFileFromNotification,
        );

        return _taskId;
      }
    } else {
      Fluttertoast.showToast(msg: '无下载权限');
    }
  }

  // 检查权限
  static Future<bool> _requestPermission() async {
    Map<Permission, PermissionStatus> statuses =
        await [Permission.storage].request();
    return statuses[Permission.storage] == PermissionStatus.granted;
  }

  // 打开下载的文件
  static Future<bool> openDownloadFile(String taskId) {
    return FlutterDownloader.open(taskId: taskId);
  }
}

// 打开工具
class OpenUtils {
  static const Map<String, String> AndroidFileTypes = {
    ".3gp": "video/3gpp",
    ".torrent": "application/x-bittorrent",
    ".kml": "application/vnd.google-earth.kml+xml",
    ".gpx": "application/gpx+xml",
    ".csv": "application/vnd.ms-excel",
    ".apk": "application/vnd.android.package-archive",
    ".asf": "video/x-ms-asf",
    ".avi": "video/x-msvideo",
    ".bin": "application/octet-stream",
    ".bmp": "image/bmp",
    ".c": "text/plain",
    ".class": "application/octet-stream",
    ".conf": "text/plain",
    ".cpp": "text/plain",
    ".doc": "application/msword",
    ".docx":
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    ".xls": "application/vnd.ms-excel",
    ".xlsx":
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    ".exe": "application/octet-stream",
    ".gif": "image/gif",
    ".gtar": "application/x-gtar",
    ".gz": "application/x-gzip",
    ".h": "text/plain",
    ".htm": "text/html",
    ".html": "text/html",
    ".jar": "application/java-archive",
    ".java": "text/plain",
    ".jpeg": "image/jpeg",
    ".jpg": "image/jpeg",
    ".js": "application/x-javascript",
    ".log": "text/plain",
    ".m3u": "audio/x-mpegurl",
    ".m4a": "audio/mp4a-latm",
    ".m4b": "audio/mp4a-latm",
    ".m4p": "audio/mp4a-latm",
    ".m4u": "video/vnd.mpegurl",
    ".m4v": "video/x-m4v",
    ".mov": "video/quicktime",
    ".mp2": "audio/x-mpeg",
    ".mp3": "audio/x-mpeg",
    ".mp4": "video/mp4",
    ".mpc": "application/vnd.mpohun.certificate",
    ".mpe": "video/mpeg",
    ".mpeg": "video/mpeg",
    ".mpg": "video/mpeg",
    ".mpg4": "video/mp4",
    ".mpga": "audio/mpeg",
    ".msg": "application/vnd.ms-outlook",
    ".ogg": "audio/ogg",
    ".pdf": "application/pdf",
    ".png": "image/png",
    ".pps": "application/vnd.ms-powerpoint",
    ".ppt": "application/vnd.ms-powerpoint",
    ".pptx":
        "application/vnd.openxmlformats-officedocument.presentationml.presentation",
    ".prop": "text/plain",
    ".rc": "text/plain",
    ".rmvb": "audio/x-pn-realaudio",
    ".rtf": "application/rtf",
    ".sh": "text/plain",
    ".tar": "application/x-tar",
    ".tgz": "application/x-compressed",
    ".txt": "text/plain",
    ".wav": "audio/x-wav",
    ".wma": "audio/x-ms-wma",
    ".wmv": "audio/x-ms-wmv",
    ".wps": "application/vnd.ms-works",
    ".xml": "text/plain",
    ".z": "application/x-compress",
    ".zip": "application/x-zip-compressed",
    "": "*/*"
  };

  static const Map<String, String> IosFileTypes = {
    ".rtf": "public.rtf",
    ".txt": "public.plain-text",
    ".html": "public.html",
    ".htm": "public.html",
    ".xml": "public.xml",
    ".tar": "public.tar-archive",
    ".gz": "org.gnu.gnu-zip-archive",
    ".gzip": "org.gnu.gnu-zip-archive",
    ".tgz": "org.gnu.gnu-zip-tar-archive",
    ".jpg": "public.jpeg",
    ".jpeg": "public.jpeg",
    ".png": "public.png",
    ".avi": "public.avi",
    ".mpg": "public.mpeg",
    ".mpeg": "public.mpeg",
    ".mp4": "public.mpeg-4",
    ".3gpp": "public.3gpp",
    ".3gp": "public.3gpp",
    ".mp3": "public.mp3",
    ".zip": "com.pkware.zip-archive",
    ".gif": "com.compuserve.gif",
    ".bmp": "com.microsoft.bmp",
    ".ico": "com.microsoft.ico",
    ".doc": "com.microsoft.word.doc",
    ".xls": "com.microsoft.excel.xls",
    ".ppt": "com.microsoft.powerpoint.​ppt",
    ".wav": "com.microsoft.waveform-​audio",
    ".wm": "com.microsoft.windows-​media-wm",
    ".wmv": "com.microsoft.windows-​media-wmv",
    ".pdf": "com.adobe.pdf"
  };
}

class FileUtils {
  // sd卡根目录
  static Future<String> get storagePath async => await getStoragePath();

  // 下载保存路径
  static Future<String> get downloadPath async {
    String? _storagePath = await storagePath;
    return _storagePath + '/Download';
  }

  // 判断是否有该目录，没有就创建
  static mkdirp(String path) async {
    Directory directory = Directory(path);
    bool isExisted = await directory.exists();
    if (!isExisted) {
      directory.create();
    }
  }

  // 保存文件
  static Future<dynamic> saveFile({
    required String filePath,
    Function(String, DownloadTaskStatus, int)? callback,
    bool showNotification = false,
    bool openFileFromNotification = false,
  }) async {
    Completer completer = Completer();

    // 如果是网络路径
    if (filePath.startsWith('http://') || filePath.startsWith('https://')) {
      // 初始下载工具
      await DownloadUtils.init();
      // 开始下载
      DownloadUtils.download(
        url: filePath,
        showNotification: showNotification,
        callback: (String id, DownloadTaskStatus status, int progress) {
          // 触发回调
          if (callback != null) {
            callback(id, status, progress);
          }

          // 下载完成
          if (status == DownloadTaskStatus.complete) {
            ImageGallerySaver.saveFile(
                    DownloadUtils.downloadPath + '/' + DownloadUtils.filename)
                .then((_) => completer.complete());
          }
        },
      );
    } else {
      // 直接保存本地文件
      ImageGallerySaver.saveFile(filePath).then((_) => completer.complete());
    }

    return completer.future;
  }
}
